/**
 * CreateTime   : 2021年1月21日
 * Des          : 资源加载释放管理类
 */
import { Asset, assetManager, AssetManager, Prefab, isValid, instantiate, resources, JsonAsset, SpriteFrame, Sprite, Vec3, v3 } from "cc";
import { Handler } from "./event/Handler";

export class AssetMgr {
    public resLoading = new Map<string, boolean>();    // 资源加载中的列表，防止重复加载

    /**
     * <资源uuid，加载回调>
     */
    private _loadCallBackMap = new Map<string, Handler>();

    /**
     * <资源路径，资源对象?
     */
    private _assetRef = new Map<string, Asset>();


    /**
     * 加载预制体
     * @param path 资源路径
     * @param name 资源名
     * @param completeCallback 回调
     */
    public LoadPrefabBundle(path: string, name: string, completeCallback: Handler) {
        let myThis = this;
        assetManager.loadBundle(path, function (err: Error, bundle: AssetManager.Bundle) {
            bundle.load<Prefab>(name, Prefab, function (error: Error, resource: Prefab) {
                if (isValid(resource)) {
                    resource.addRef();
                    let instance = instantiate(resource);
                    myThis._assetRef.set(instance.uuid, resource);
                    completeCallback.runWith(instance);
                    instance.setPosition(v3(0, 0, 0));
                }
                else {
                    completeCallback.recover();
                }
            }.bind(myThis))
        }.bind(this));
    }

    /**
     * 加载resources预制体
     * @param path 资源路径
     * @param name 资源名
     * @param completeCallback 回调
     */
    public LoadPrefabAsset(name: string, completeCallback: Handler) {
        let myThis = this;
        resources.load<Prefab>(name, Prefab, function (error: Error, resource: Prefab) {
            if (isValid(resource)) {
                resource.addRef();
                let instance = instantiate(resource);
                myThis._assetRef.set(instance.uuid, resource);
                completeCallback.runWith(instance);
            }
            else {
                console.error("load spine error ", error, name);
                // resources.release(name);
                completeCallback.recover();
            }
        }.bind(this))
    }

    /**
     * 加载json
     * @param path 资源路径
     * @param name 资源名
     * @param completeCallback 回调
     */
    public LoadJsonBundle(path: string, name: string, completeCallback: Handler) {
        assetManager.loadBundle(path, function (err: Error, bundle: AssetManager.Bundle) {
            bundle.load<JsonAsset>(name, JsonAsset, function (error: Error, json: any) {
                completeCallback.runWith(json);
                assetManager.removeBundle(bundle);
            })
        });
    }

    /**
     * 加载Bundle贴图是
     * @param path 资源路径
     * @param name 资源名 SpriteFrame格式的要添加/spriteFrame
     * @param sprite 加载对象
     * @param completeCallback 回调
     */
    public LoadTextureBundle(path: string, name: string, sprite: Sprite, completeCallback: Handler) {
        let myThis = this;
        assetManager.loadBundle(path, function (err: Error, bundle: AssetManager.Bundle) {
            bundle.load<SpriteFrame>(name, SpriteFrame, function (error: Error, resource: SpriteFrame) {
                if (isValid(sprite) && isValid(resource)) {
                    sprite.spriteFrame = resource;
                    myThis._assetRef.set(sprite.uuid, resource);
                    myThis._loadCallBackMap.delete(sprite.uuid);
                    if (completeCallback)
                        completeCallback.runWith(sprite);
                }
                else if (completeCallback) {
                    console.error("load Texture bunle error ", path, name);
                    completeCallback.recover();
                }
            }.bind(myThis))
        }.bind(this));
    }

    /**
     * 加载resources贴图
     * @param name 资源名
     * @param sprite 加载对象
     * @param completeCallback 回调
     */
    public LoadTextureAsset(name: string, sprite: Sprite, completeCallback: Handler) {
        let url = name;
        resources.load<SpriteFrame>(url, SpriteFrame, function (error: Error, resource: SpriteFrame) {
            if (isValid(sprite) && isValid(resource)) {
                sprite.spriteFrame = resource;
                if (completeCallback)
                    completeCallback.runWith(sprite);
            }
            else if (completeCallback) {
                // console.error("load Texture error ", name);
                completeCallback.recover();
            }
        }.bind(this))
    }


    ReleaseAsset(url: string, uuid: string) {
        if (this._assetRef.has(uuid)) {
            let asset = this._assetRef.get(uuid);
            asset.decRef();
            this._assetRef.delete(uuid);
        }

        if (this._loadCallBackMap.has(uuid)) {
            this._loadCallBackMap.get(uuid).recover();
            this._loadCallBackMap.delete(uuid);
        }
    }
}